#!/usr/bin/env python
import os
import sys
import string
import time
import datetime
import MySQLdb
import redis
import logging
import logging.config
logging.config.fileConfig("etc/logger.ini")
logger = logging.getLogger("lepus")
path='./include'
sys.path.insert(0,path)
import functions as func
from multiprocessing import Process;

db_type = 'redis'
warning = 'warning'
critical = 'critical'
ok = 'ok'
connectivity = 'connectivity'
table_server = 'redis_server'
table_status = 'redis_status'
mail_receiver_list = func.get_config('mail_server','mail_receiver_list')
sms_receiver_list = func.get_config('sms_server','sms_receiver_list')

def check_value(info,key):
    try:
        key_tmp = key
        key_tmp = info['%s' %(key)]
        if key_tmp==key:
           key_tmp='-1'
           logger_msg="check redis %s:%s : %s is not supported for this version" %(host,port,key)
           logger.warning(logger_msg)
    except:
        key_tmp='-1'
        logger_msg="check redis %s:%s : %s is not supported for this version" %(host,port,key)
        logger.waring(logger_msg)

    finally:
        return key_tmp
    
     

def check_redis(host,port,passwd,tags):
    url=host+':'+port+'/'+tags
    server = func.get_current_server(table_server,host,port)
    send_mail = server[6]
    send_mail_to_list = server[7]
    send_sms = server[8]
    send_sms_to_list = server[9]
    alarm_connected_clients = server[10]
    alarm_command_processed = server[11]
    alarm_blocked_clients = server[12]
    threshold_connected_clients = server[13]
    threshold_command_processed = server[14]
    threshold_blocked_clients = server[15]
    now_time = func.get_now_time()

    if send_mail_to_list is None or  send_mail_to_list.strip()=='':
       send_mail_to_list = mail_receiver_list
    if send_sms_to_list is None or  send_sms_to_list.strip()=='':
       send_sms_to_list = sms_receiver_list

    try:
        r=redis.StrictRedis(host=host,port=int(port),password=passwd,db=0,socket_timeout=3,charset='utf-8') 
        info=r.info()
        time.sleep(1)
        info_2=r.info()
        # Server
        redis_version = info['redis_version']
        redis_git_sha1 = info['redis_git_sha1']
        redis_git_dirty = info['redis_git_dirty']
        arch_bits = info['arch_bits']
        multiplexing_api = info['multiplexing_api']
        gcc_version = info['gcc_version']
        process_id = info['process_id']
        uptime_in_seconds = info['uptime_in_seconds']
        uptime_in_days = info['uptime_in_days']
        lru_clock = info['lru_clock']
        os = check_value(info,'os')
        redis_mode = check_value(info,'redis_mode')
        hz = check_value(info,'hz')
        run_id = check_value(info,'run_id')
        tcp_port = check_value(info,'tcp_port')

        # Clients 
        connected_clients = info['connected_clients']
        client_longest_output_list = info['client_longest_output_list']
        client_biggest_input_buf = info['client_biggest_input_buf']
        blocked_clients = info['blocked_clients']
        # Memory
        used_memory = info['used_memory']
        used_memory_human = info['used_memory_human']
        used_memory_rss = info['used_memory_rss']
        used_memory_peak = info['used_memory_peak']
        used_memory_peak_human = info['used_memory_peak_human']
        used_memory_lua = check_value(info,'used_memory_lua')
        mem_fragmentation_ratio = info['mem_fragmentation_ratio']
        mem_allocator = info['mem_allocator']
        # Persistence
        loading = info['loading']
        rdb_changes_since_last_save = check_value(info,'rdb_changes_since_last_save')
        rdb_bgsave_in_progress = check_value(info,'rdb_bgsave_in_progress')
        rdb_last_save_time = check_value(info,'rdb_last_save_time')
        rdb_last_bgsave_status = check_value(info,'rdb_last_bgsave_status')
        rdb_last_bgsave_time_sec = check_value(info,'rdb_last_bgsave_time_sec')
        rdb_current_bgsave_time_sec = check_value(info,'rdb_current_bgsave_time_sec')
        aof_enabled = check_value(info,'aof_enabled')
        aof_rewrite_in_progress = check_value(info,'aof_rewrite_in_progress')
        aof_rewrite_scheduled = check_value(info,'aof_rewrite_scheduled')
        aof_last_rewrite_time_sec = check_value(info,'aof_last_rewrite_time_sec')
        aof_current_rewrite_time_sec = check_value(info,'aof_current_rewrite_time_sec')
        aof_last_bgrewrite_status = check_value(info,'aof_last_bgrewrite_status')
        # Stats
        total_connections_received = check_value(info,'total_connections_received')
        total_commands_processed = check_value(info,'total_commands_processed')
        current_commands_processed = int(info_2['total_commands_processed'] - info['total_commands_processed'])
        instantaneous_ops_per_sec = check_value(info,'instantaneous_ops_per_sec')
        rejected_connections = check_value(info,'rejected_connections')

        expired_keys = info['expired_keys']
        evicted_keys = info['evicted_keys']
        keyspace_hits = info['keyspace_hits']
        keyspace_misses = info['keyspace_misses']
        pubsub_channels = info['pubsub_channels']
        pubsub_patterns = info['pubsub_patterns']
        latest_fork_usec = info['latest_fork_usec']
        # Replication
        role = info['role']
        connected_slaves = info['connected_slaves']
        
        # CPU
        used_cpu_sys = info['used_cpu_sys']
        used_cpu_user = info['used_cpu_user']
        used_cpu_sys_children = info['used_cpu_sys_children']
        used_cpu_user_children = info['used_cpu_user_children']


        #add redis_status
        connect=1
        sql = "insert into redis_status(host,port,tags,redis_role,connect,redis_version,redis_git_sha1,redis_git_dirty,redis_mode,os,arch_bits,multiplexing_api,gcc_version,process_id,run_id,tcp_port,uptime_in_seconds,uptime_in_days,hz,lru_clock,connected_clients,client_longest_output_list,client_biggest_input_buf,blocked_clients,used_memory,used_memory_human,used_memory_rss,used_memory_peak,used_memory_peak_human,used_memory_lua,mem_fragmentation_ratio,mem_allocator,loading,rdb_changes_since_last_save,rdb_bgsave_in_progress,rdb_last_save_time,rdb_last_bgsave_status,rdb_last_bgsave_time_sec,rdb_current_bgsave_time_sec,aof_enabled,aof_rewrite_in_progress,aof_rewrite_scheduled,aof_last_rewrite_time_sec,aof_current_rewrite_time_sec,aof_last_bgrewrite_status,total_connections_received,total_commands_processed,current_commands_processed,instantaneous_ops_per_sec,rejected_connections,expired_keys,evicted_keys,keyspace_hits,keyspace_misses,pubsub_channels,pubsub_patterns,latest_fork_usec,used_cpu_sys,used_cpu_user,used_cpu_sys_children,used_cpu_user_children) values(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s);"
        param = (host,port,tags,role,connect,redis_version,redis_git_sha1,redis_git_dirty,redis_mode,os,arch_bits,multiplexing_api,gcc_version,process_id,run_id,tcp_port,uptime_in_seconds,uptime_in_days,hz,lru_clock,connected_clients,client_longest_output_list,client_biggest_input_buf,blocked_clients,used_memory,used_memory_human,used_memory_rss,used_memory_peak,used_memory_peak_human,used_memory_lua,mem_fragmentation_ratio,mem_allocator,loading,rdb_changes_since_last_save,rdb_bgsave_in_progress,rdb_last_save_time,rdb_last_bgsave_status,rdb_last_bgsave_time_sec,rdb_current_bgsave_time_sec,aof_enabled,aof_rewrite_in_progress,aof_rewrite_scheduled,aof_last_rewrite_time_sec,aof_current_rewrite_time_sec,aof_last_bgrewrite_status,total_connections_received,total_commands_processed,current_commands_processed,instantaneous_ops_per_sec,rejected_connections,expired_keys,evicted_keys,keyspace_hits,keyspace_misses,pubsub_channels,pubsub_patterns,latest_fork_usec,used_cpu_sys,used_cpu_user,used_cpu_sys_children,used_cpu_user_children)
        func.mysql_exec(sql,param)
        
        try:
           if int(alarm_connected_clients) == 1 and ( int(connected_clients) >= int(threshold_connected_clients) ):
              message = "%s connected clients"%(connected_clients)
              func.add_alarm(db_type,tags,host,port,now_time,'connected clients',message,warning,message,message,send_mail,send_sms)
              if send_mail == 1:
                 func.send_alarm_mail(db_type,tags,host,port,now_time,warning,message,message,send_mail_to_list)
              if send_sms == 1:
                 func.send_alarm_sms(db_type,tags,host,port,now_time,warning,message,send_sms_to_list)
        except Exception, e:
           logger.error(str(e).strip('\n'))
           sys.exit(1)

        try:
           if int(alarm_blocked_clients) == 1 and ( int(blocked_clients) >= int(threshold_blocked_clients) ):
              message = "%s blocked clients"%(blocked_clients)           
              func.add_alarm(db_type,tags,host,port,now_time,'blocked clients',message,warning,message,message,send_mail,send_sms)
              if send_mail == 1:
                 func.send_alarm_mail(db_type,tags,host,port,now_time,warning,message,message,send_mail_to_list)
              if send_sms == 1:
                 func.send_alarm_sms(db_type,tags,host,port,now_time,warning,message,send_sms_to_list)
        except Exception, e:
           logger.error(str(e).strip('\n'))
           sys.exit(1)

        try:
           if int(alarm_command_processed) == 1 and ( int(current_commands_processed) >= int(threshold_command_processed) ):
              message = "%s current commands"%(current_commands_processed)                          
              func.add_alarm(db_type,tags,host,port,now_time,'current commands',message,warning,message,message,send_mail,send_sms)
              if send_mail == 1:
                 func.send_alarm_mail(db_type,tags,host,port,now_time,warning,message,message,send_mail_to_list)
              if send_sms == 1:
                 func.send_alarm_sms(db_type,tags,host,port,now_time,warning,message,send_sms_to_list)
        except Exception, e:
           logger.error(str(e).strip('\n'))
           sys.exit(1)


    except Exception, e:
        error_msg = str(e).strip('\n')
        logger_msg="check redis %s : %s" %(url,error_msg)
        logger.warning(logger_msg)
        func.add_alarm(db_type,tags,host,port,now_time,connectivity,'error',critical,'connect error',error_msg,send_mail,send_sms)
        if send_mail==1:
           func.send_alarm_mail(db_type,tags,host,port,now_time,critical,'connect error',error_msg,send_mail_to_list)
        if send_sms==1:
           func.send_alarm_sms(db_type,tags,host,port,now_time,critical,'connect error',send_sms_to_list)
   
        try:
            connect=0
            sql="insert into redis_status(host,port,tags,connect) values(%s,%s,%s,%s)"
            param=(host,port,tags,connect)
            func.mysql_exec(sql,param)

        except Exception, e:
            logger.error(e)
            sys.exit(1)
        finally:
            sys.exit(1)

    finally:
        func.check_db_status(host,port,tags,'redis')   
        sys.exit(1)


def main():

    func.mysql_exec("insert into redis_status_history SELECT *,LEFT(REPLACE(REPLACE(REPLACE(create_time,'-',''),' ',''),':',''),12) from redis_status;",'')
    func.mysql_exec('delete from redis_status;','')

    servers = func.mysql_query('select host,port,password,tags from redis_server where  monitor=1;')

    logger.info("check redis controller started.")

    if servers:
         plist = []

         for row in servers:
             host=row[0]
             port=row[1]
             passwd=row[2]
             tags=row[3]
             p = Process(target = check_redis, args = (host,port,passwd,tags))
             plist.append(p)
             p.start()

         for p in plist:
             p.join()

    else:
         logger.warning("check redis: not found any servers")

    logger.info("check redis controller finished.")

if __name__=='__main__':
    main()
